<script setup lang="ts">
import { reactive, toRaw, watch } from 'vue'
import type { Edge, Node } from '@antv/x6'
import { Graph, Path } from '@antv/x6'
import { DeleteOutlined, ExportOutlined, EyeOutlined, FullscreenExitOutlined, FullscreenOutlined, GatewayOutlined, PicCenterOutlined, PlayCircleOutlined, PoweroffOutlined, RedoOutlined, ReloadOutlined, SaveOutlined, ShrinkOutlined, UndoOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons-vue'
import { App } from 'ant-design-vue'
import type { FormInstance } from 'ant-design-vue'
import { uuid } from 'vue-uuid'
import { register } from '@antv/x6-vue-shape'
import { History } from '@antv/x6-plugin-history'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Selection } from '@antv/x6-plugin-selection'
import CurrentNode from './current-node.vue'
import MonacoEditor from '@/components/monaco-editor/index.vue'
import { exitFullscreen, launchIntoFullscreen } from '@/utils/util.ts'

const props = withDefaults(defineProps<{
  graphData?: object
  graphModel?: string
}>(), {
  graphModel: 'edit',
})
// 暴露保存方法
const emit = defineEmits(['save'])

const { message } = App.useApp()

const graph = ref()
const dragSubX = ref(0)
const dragSubY = ref(0)
const selectCellId = ref() // 被选中的元素id
const selectEdgeLabel = ref() // 被选中的边的label
const selectCellType = ref() // 被选中的节点类型
const fullscreenStatus = ref(false) // 全屏状态
const toggleIcon = ref('left') // 隐藏显示图标
const showInfo = ref(false) // 是否显示节点详情面板
const canUndo = ref(false) // 是否可撤销
const canRedo = ref(false) // 是否可重做
const previewVisiable = ref(false) // 预览框可见性
const jsonData = ref() // 画布数据
const windowHeight = ref(`${window.innerHeight - 300}px`)

// 右键菜单位置和展示
const style = reactive({ top: '0px', left: '0px' })
const visiableContextMenu = ref(false)

// 边双击输入switch分支
const switchCase = ref()
const switchCaseValue = ref<string>()

// 被选中的cell表单数据
const selectFormData = reactive({
  label: '',
  name: '', // 名称
  workflowName: undefined, // 流程名称
  version: 1, // 版本
  taskReferenceName: undefined, // 引用名称
  description: undefined, // 描述
  nodeType: '', // 任务类型
  caseValueParam: undefined, // 条件
  caseExpression: undefined, // 条件表达式
  joinOn: '', // 合并任务
  loopCondition: undefined, // 循环条件
  loopTasks: [], // 循环任务
  evaluatorType: undefined, // 评估器类型
  expression: undefined, // 评估表达式
  inputParameters: '', // 入参
  method: undefined,
  appName: undefined,
  uri: undefined,
  headers: undefined,
  body: undefined,
  accept: undefined,
  contentType: undefined,
  connectionTimeOut: undefined,
  readTimeOut: undefined,
})

const formRef = ref<FormInstance>()
const labelCol = { span: 24 }
async function saveTask() {
  formRef.value?.validateFields()
    .then(() => {
      if (selectCellId.value !== undefined) {
        const currentCell = graph.value.getCellById(selectCellId.value)
        currentCell.data = toRaw(selectFormData)
        selectCellId.value = undefined
        showInfo.value = false
      }
    })
    .catch((err) => {
      console.log('error', err)
    })
}

onMounted(() => {
  preInit()
  init()
  // 监听全屏事件
  document.addEventListener('fullscreenchange', () => {
    if (fullscreenStatus.value) {
      graph.value.resize(100, window.innerHeight - 320)
      fullscreenStatus.value = false
    }
    else { fullscreenStatus.value = true }
  })
})

onUnmounted(() => {
  if (graph.value)
    graph.value.dispose()

  // 移除全屏事件
  document.removeEventListener('fullscreenchange', () => {
  })
})

watch(() => props.graphData, (newValue) => {
  // 使用graph.value.fromJSON()方法初始化流程图，实现编辑操作打开已存在的流程
  if (newValue)
    graph.value.fromJSON(newValue)
})

/*****************
 * 画布相关
 */
// 初始化之前
function preInit() {
  Graph.unregisterConnector('algo-connector')
  // 注册连接器
  Graph.registerConnector(
    'algo-connector',
    (s, e) => {
      const offset = 4
      const deltaY = Math.abs(e.y - s.y)
      const control = Math.floor((deltaY / 3) * 2)
      const v1 = { x: s.x, y: s.y + offset + control }
      const v2 = { x: e.x, y: e.y - offset - control }
      return Path.normalize(
          `M ${s.x} ${s.y}
           L ${s.x} ${s.y + offset}
           C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
           L ${e.x} ${e.y}
          `,
      )
    },
    true,
  )
  Graph.unregisterEdge('dag-edge')
  Graph.unregisterEdge('do-while-edge')
  // 注册边
  Graph.registerEdge(
    'dag-edge',
    {
      inherit: 'edge',
      attrs: {
        line: {
          stroke: '#C2C8D5',
          strokeWidth: 1,
          targetMarker: 'block',
        },
      },
    },
  )
  // 注册循环节点边
  Graph.registerEdge(
    'do-while-edge',
    {
      inherit: 'edge',
      attrs: {
        line: {
          stroke: '#C2C8D5',
          strokeWidth: 1,
          targetMarker: 'block',
        },
      },
    },
  )
  // 注册普通节点
  register({
    shape: 'custom-vue-node',
    width: 120,
    height: 36,
    component: CurrentNode,
    ports: {
      groups: {
        in: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        out: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
      },
      items: [
        { id: 'port1', group: 'in' },
        { id: 'port2', group: 'out' },
      ],
    },
  })
  // 循环任务节点
  register({
    shape: 'do-while-vue-node',
    width: 120,
    height: 36,
    component: CurrentNode,
    ports: {
      groups: {
        in: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        out: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#C2C8D5',
              strokeWidth: 1,
              fill: '#fff',
            },
          },
        },
      },
      items: [
        { id: 'port1', group: 'in' },
        { id: 'port2', group: 'out' },
        { id: 'port3', group: 'left' },
        { id: 'port4', group: 'right' },
      ],
    },
  })
}
// 初始化
function init() {
  // 创建画布
  graph.value = new Graph({
    container: document.getElementById('container') as HTMLElement,
    autoResize: true, // 监听容器大小改变
    background: {
      color: isDark.value ? '#242525' : 'white', // 设置画布背景颜色
    },
    panning: {
      enabled: true,
    },
    mousewheel: {
      enabled: true,
      modifiers: ['ctrl'],
    },
    grid: {
      size: 10, // 网格大小 10px
      visible: true, // 渲染网格背景
    },
    connecting: {
      snap: true,
      allowBlank: false,
      allowNode: false,
      allowMulti: 'withPort',
      allowLoop: false,
      highlight: true,
      router: 'manhattan',
      connector: {
        name: 'rounded',
        args: {
          radius: 8,
        },
      },
      connectionPoint: 'anchor',
      anchor: 'center',
      validateMagnet({ magnet }) {
        return magnet.getAttribute('port-group') !== 'top'
      },
      createEdge(e) {
        console.log(e)
        const sourceNode = e.sourceCell as Node
        const sourceMagent = e.sourceMagnet
        console.log(sourceMagent.attributes.getNamedItem('port')?.value)
        let shapeStr = 'dag-edge'
        if (sourceNode.getData().nodeType === 'DO_WHILE'
          && (sourceMagent.attributes.getNamedItem('port')?.value === 'port3' || sourceMagent.attributes.getNamedItem('port')?.value === 'port4'))
          shapeStr = 'do-while-edge'

        const edge = graph.value.createEdge({
          shape: shapeStr,
          attrs: {
            line: {
              strokeDasharray: '5 5',
            },
          },
          zIndex: -1,
        })
        return edge
      },
    },
  })
  // 启用撤销重做
  graph.value.use(
    new History({
      enabled: true,
    }),
  )
  // 启用对齐线
  graph.value.use(
    new Snapline({
      enabled: true,
    }),
  )
  // 启用选择
  graph.value.use(
    new Selection({
      enabled: true,
      multiple: true,
    }),
  )
  // 边连接事件
  graph.value.on('edge:connected', ({ edge }) => {
    edge.attr({
      line: {
        strokeDasharray: '',
      },
    })
  })
  // 节点data修改事件
  graph.value.on('node:change:data', ({ node }) => {
    const edges = graph.value.getOutgoingEdges(node)
    const status = node.getData().status
    if (edges !== null) {
      edges.forEach((edge: any) => {
        if (status === 'running') {
          edge.attr('line/strokeDasharray', 5)
          edge.attr('line/style/animation', 'running-line 30s infinite linear')
        }
        else {
          edge.attr('line/strokeDasharray', '')
          edge.attr('line/style/animation', '')
        }
      })
    }
  })
  // 节点左键单击事件
  graph.value.on('node:click', ({ node }) => {
    selectCellType.value = node.data.nodeType
    selectCellId.value = node.id
    formRef.value?.resetFields()
    Object.assign(selectFormData, node.data)
    showInfo.value = true
  })
  // 边左键单击事件
  graph.value.on('edge:click', ({ edge }) => {
    // 赋值select，用于选中删除功能
    selectCellId.value = edge.id
  })
  // 边左键双击事件
  graph.value.on('edge:dblclick', ({ e, edge }) => {
    const source = edge.getSource()
    const sourceNode = graph.value.getCellById(source.cell) as Node
    if (sourceNode.getData().nodeType !== 'SWITCH') {
      // 只针对switch任务的后继任务可以设置label
      return
    }

    if (edge.getLabels().length !== 0) {
      const labelText = edge.getLabels()[0].attrs.label.text
      switchCaseValue.value = labelText
      edge.removeLabelAt(0)
    }
    style.top = `${e.offsetY - 10}px`
    style.left = `${e.offsetX - 40}px`
    visiableContextMenu.value = true
    selectCellId.value = edge.id
    nextTick(() => {
      switchCase.value.focus()
    })
  })
  // 节点右键单击事件
  graph.value.on('node:contextmenu', ({ e, node }) => {
    console.log(e)
    console.log(node)
  })
  // 边右键单击事件
  graph.value.on('edge:contextmenu', ({ e, edge }) => {
    console.log(e)
    console.log(edge)
  })
  // 空白处左键单击事件
  graph.value.on('blank:click', () => {
    // 重制选中
    selectEdgeLabel.value = ''
    showInfo.value = false
    visiableContextMenu.value = false
    selectCellId.value = undefined
    selectCellType.value = undefined
  })

  // 使用graph.value.fromJSON()方法初始化流程图，实现编辑操作打开已存在的流程
  if (props.graphData)
    graph.value.fromJSON(props.graphData)
}
// 放大
function zoomAdd() {
  graph.value.zoom(0.1)
}
// 缩小
function zoomDelete() {
  graph.value.zoom(-0.1)
}
// 撤销
function undo() {
  if (graph.value.canUndo()) {
    graph.value.undo()
    canRedo.value = true
    if (!graph.value.canUndo())
      canUndo.value = false
  }
}
// 重做
function redo() {
  if (graph.value.canRedo()) {
    graph.value.redo()
    canUndo.value = true
    if (!graph.value.canRedo())
      canRedo.value = false
  }
}
// 居中
function centerContent() {
  graph.value.centerContent()
}
// 重置缩放比例
function reZoom() {
  graph.value.zoomTo(1)
}
// 适应画布
function zoomToFit() {
  graph.value.zoomToFit()
}
// 删除
function deleteCell() {
  if (selectCellId.value !== undefined) {
    graph.value.removeCell(selectCellId.value)
    selectCellId.value = undefined
    showInfo.value = false
    visiableContextMenu.value = false
  }
}
// 重置画布
function refreshGraph() {
  graph.value.dispose()
  canUndo.value = false
  canRedo.value = false
  init()
}
// 画布全屏
function fullscreen() {
  const container = document.getElementById('x6-container')
  launchIntoFullscreen(container)
  // graph.value.resize('100vw', window.screen.height - 40)
}
// 保存
function save() {
  const data = graph.value.toJSON()
  emit('save', { data })
}
// 导出 TODO
function exportJson() {
  const data = graph.value.toJSON()
  if (data.cells !== undefined && data.cells.length > 0) {
    jsonData.value = JSON.stringify(data, null, 2)
    previewVisiable.value = true
  }
  else {
    message.warning('画布内容为空')
  }
}
// tool bar绑定父container，默认为body
function getPopupContainer() {
  return document.getElementById('x6-container') as HTMLElement
}
/***********
 * 画布相关
 */

/**********
  * 拖拽相关
  */
// 开始拖拽
function dragstart(ev) {
  const nodeTypeElement = ev.target.getElementsByTagName('div')[0]
  const nodeType = nodeTypeElement.getAttribute('node-type')
  const labelElement = ev.target.getElementsByTagName('span')[1]
  const label = labelElement.innerHTML
  dragSubX.value = ev.x - ev.currentTarget.getBoundingClientRect().x
  dragSubY.value = ev.y - ev.currentTarget.getBoundingClientRect().y
  ev.dataTransfer.setData('nodeType', nodeType)
  ev.dataTransfer.setData('label', label)
}
// 拖拽
function dragover(ev) {
  ev.preventDefault()
}
// 释放
function drop(ev) {
  const point = graph.value.pageToLocal(ev.pageX - dragSubX.value, ev.pageY - dragSubY.value)
  const nodeType = ev.dataTransfer.getData('nodeType')
  const label = ev.dataTransfer.getData('label')
  const node = {
    id: uuid.v4(),
    x: point.x,
    y: point.y,
    data: {
      label,
      nodeType,
      status: 'normal',
    },
  }
  createNode(node)
}
// 创建节点
function createNode(node) {
  let shapeStr = 'custom-vue-node'
  if (node.data.nodeType === 'DO_WHILE')
    shapeStr = 'do-while-vue-node'

  const nodeInfo = {
    shape: shapeStr,
  }
  Object.assign(nodeInfo, node)
  graph.value.addNode(nodeInfo)
  if (!canUndo.value && graph.value.canUndo())
    canUndo.value = true
}
/**********
  * 拖拽相关
  */

/**********
  * 详情相关
  */
// 隐藏详情
function closeInfo() {
  showInfo.value = false
}

// 保存边上的label
function confirmSwitchCase() {
  const text = switchCaseValue.value
  if (text) {
    const label = {
      attrs: {
        label: {
          text,
          fill: '#000',
        },
      },
    }
    const edge = graph.value.getCellById(selectCellId.value) as Edge
    edge.insertLabel(label)
    visiableContextMenu.value = false
    switchCaseValue.value = ''
  }
}
/**********
  * 详情相关
  */
// 监听isDark的变化
watch(isDark, () => {
  // TODO 设置边上label的颜色
  console.log(graph.value.getEdges())
  if (isDark.value) {
    graph.value.drawBackground({
      color: '#242525',
    })
  }
  else {
    graph.value.drawBackground({
      color: 'white',
    })
  }
})
</script>

<template>
  <a-layout id="x6-container" class="my-x6-layout">
    <!-- 左侧菜单start -->
    <a-layout-sider v-if="graphModel === `edit`" class="menu-container" :class="`${toggleIcon === 'left' ? `` : `hide-menu`}`">
      <div class="menu-slot">
        系统任务
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="开始任务"
          node-type="start"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <PlayCircleOutlined />
          </template>
        </menu-node>
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="决策任务"
          node-type="SWITCH"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <CarbonDecide />
          </template>
        </menu-node>
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="HTTP任务"
          node-type="HTTP"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <CarbonHttp />
          </template>
        </menu-node>
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="分支任务"
          node-type="FORK"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <CarbonFork />
          </template>
        </menu-node>
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="合并任务"
          node-type="JOIN"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <CarbonJoin />
          </template>
        </menu-node>
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="循环任务"
          node-type="DO_WHILE"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <CarbonLoop />
          </template>
        </menu-node>
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="中止任务"
          node-type="TERMINATE"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <CarbonTerminate />
          </template>
        </menu-node>
      </div>
      <div class="menu-item">
        <menu-node
          draggable="true"
          label="结束任务"
          node-type="finish"
          @dragstart="dragstart($event)"
        >
          <template #prefix>
            <PoweroffOutlined />
            <!-- <CarbonFinish /> -->
          </template>
        </menu-node>
      </div>
    </a-layout-sider>
    <a-layout style="position: relative; border-radius: 0 8px 8px 0;">
      <!-- 顶部工具栏start -->
      <a-layout-header class="tool-bar">
        <div class="tool-group">
          <a-tooltip :get-popup-container="getPopupContainer">
            <template #title>
              放大
            </template>
            <button class="x6-toolbar-item" @click="zoomAdd">
              <ZoomInOutlined />
            </button>
          </a-tooltip>
          <a-tooltip :get-popup-container="getPopupContainer">
            <template #title>
              缩小
            </template>
            <button class="x6-toolbar-item" @click="zoomDelete">
              <ZoomOutOutlined />
            </button>
          </a-tooltip>
          <a-tooltip v-if="graphModel === `edit`" :get-popup-container="getPopupContainer">
            <template #title>
              撤销
            </template>
            <button :class="`x6-toolbar-item ${canUndo ? `` : `x6-toolbar-item-disabled`}`" @click="undo">
              <UndoOutlined />
            </button>
          </a-tooltip>
          <a-tooltip v-if="graphModel === `edit`" :get-popup-container="getPopupContainer">
            <template #title>
              重做
            </template>
            <button :class="`x6-toolbar-item ${canRedo ? `` : `x6-toolbar-item-disabled`}`" @click="redo">
              <RedoOutlined />
            </button>
          </a-tooltip>
          <a-tooltip :get-popup-container="getPopupContainer">
            <template #title>
              居中
            </template>
            <button class="x6-toolbar-item" @click="centerContent">
              <PicCenterOutlined />
            </button>
          </a-tooltip>
          <a-tooltip :get-popup-container="getPopupContainer">
            <template #title>
              还原缩放
            </template>
            <button class="x6-toolbar-item" @click="reZoom">
              <ShrinkOutlined />
            </button>
          </a-tooltip>
          <a-tooltip :get-popup-container="getPopupContainer">
            <template #title>
              适应画布
            </template>
            <button class="x6-toolbar-item" @click="zoomToFit">
              <GatewayOutlined />
            </button>
          </a-tooltip>
          <a-tooltip v-if="graphModel === `edit`" :get-popup-container="getPopupContainer">
            <template #title>
              删除
            </template>
            <button :class="`x6-toolbar-item ${selectCellId === undefined ? 'x6-toolbar-item-disabled' : ''}`" @click="deleteCell">
              <DeleteOutlined />
            </button>
          </a-tooltip>
          <a-tooltip :get-popup-container="getPopupContainer">
            <template #title>
              小地图(暂未实现)
            </template>
            <button class="x6-toolbar-item" @click="() => {}">
              <EyeOutlined />
            </button>
          </a-tooltip>
        </div>
        <div class="tool-group tool-right">
          <a-tooltip v-if="graphModel === `edit`" :get-popup-container="getPopupContainer">
            <template #title>
              保存
            </template>
            <button class="x6-toolbar-item" @click="save">
              <SaveOutlined />
            </button>
          </a-tooltip>
          <a-tooltip v-if="graphModel === `edit`" :get-popup-container="getPopupContainer">
            <template #title>
              导出
            </template>
            <button class="x6-toolbar-item" @click="exportJson">
              <ExportOutlined />
            </button>
          </a-tooltip>
          <a-tooltip v-if="graphModel === `edit`" :get-popup-container="getPopupContainer">
            <template #title>
              重置画布
            </template>
            <a-popconfirm
              title="确认重置吗，重置将清空当前画布，未保存数据将被丢弃？"
              ok-text="是"
              placement="topRight"
              :get-popup-container="getPopupContainer"
              cancel-text="否"
              @confirm="refreshGraph"
            >
              <button class="x6-toolbar-item">
                <ReloadOutlined />
              </button>
            </a-popconfirm>
          </a-tooltip>
          <a-tooltip v-if="!fullscreenStatus" :get-popup-container="getPopupContainer" placement="topRight">
            <template #title>
              最大化
            </template>
            <button class="x6-toolbar-item" @click="fullscreen">
              <FullscreenOutlined />
            </button>
          </a-tooltip>
          <a-tooltip v-if="fullscreenStatus" :get-popup-container="getPopupContainer">
            <template #title>
              还原
            </template>
            <button class="x6-toolbar-item" @click="exitFullscreen">
              <FullscreenExitOutlined />
            </button>
          </a-tooltip>
        </div>
      </a-layout-header>
      <!-- 顶部工具栏end -->
      <!-- 主体画布start -->
      <a-layout-content>
        <div id="container" :style="{ height: windowHeight }" style="border-radius: 0 0 8px 0;" @dragover="dragover($event)" @drop="drop($event)">
          <div v-if="visiableContextMenu" class="context-menu" :style="style">
            <a-input ref="switchCase" v-model:value="switchCaseValue" placeholder="分支条件" size="small" style="width: 80px" @press-enter="confirmSwitchCase" @blur="confirmSwitchCase" />
          </div>
        </div>
      </a-layout-content>
      <div id="minimap" />
      <!-- 主体画布end -->
      <!-- 预览弹出层start -->
      <a-modal v-model:open="previewVisiable" title="预览">
        <a-textarea
          v-model:value="jsonData"
          placeholder="当前数据"
          :auto-size="{ minRows: 3, maxRows: 20 }"
        />
      </a-modal>
      <!-- 预览弹出层end -->
      <!-- 节点/边 详细信息start -->
      <a-drawer
        title="详情"
        :width="500"
        :open="showInfo"
        :body-style="{ paddingBottom: '80px' }"
        :footer-style="{ textAlign: 'right' }"
        :destroy-on-close="true"
        @close="closeInfo"
      >
        <a-form ref="formRef" :label-col="labelCol" layout="vertical" :model="selectFormData">
          <a-row :gutter="16">
            <a-col :span="12">
              <a-form-item label="任务名:" name="label" :rules="[{ required: true, message: '请输入任务名' }]">
                <a-input v-model:value="selectFormData.label" placeholder="请输入任务名" />
              </a-form-item>
            </a-col>
            <a-col v-if="selectFormData.nodeType === 'start'" :span="12">
              <a-form-item label="流程名:" name="workflowName" :rules="[{ required: true, message: '请输入流程名' }]">
                <a-input v-model:value="selectFormData.workflowName" placeholder="请输入流程名" />
              </a-form-item>
            </a-col>
            <a-col v-else :span="12">
              <a-form-item label="引用名称:" name="taskReferenceName" :rules="[{ required: true, message: '请输入引用名称' }]">
                <a-input v-model:value="selectFormData.taskReferenceName" placeholder="请输入引用名称" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'start'">
            <a-col :span="24">
              <a-form-item label="版本:" name="version" :rules="[{ required: true, message: '请输入版本' }]">
                <a-input-number v-model:value="selectFormData.version" :min="1" placeholder="请输入版本" style="width: 100%" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row>
            <a-col :span="24">
              <a-form-item label="任务类型:" name="nodeType" :rules="[{ required: true, message: '请选择任务类型' }]">
                <a-select v-model:value="selectFormData.nodeType" placeholder="请选择任务类型" disabled>
                  <a-select-option value="start">
                    开始任务
                  </a-select-option>
                  <a-select-option value="SWITCH">
                    决策任务
                  </a-select-option>
                  <a-select-option value="HTTP">
                    HTTP任务
                  </a-select-option>
                  <a-select-option value="FORK">
                    分支任务
                  </a-select-option>
                  <a-select-option value="JOIN">
                    合并任务
                  </a-select-option>
                  <a-select-option value="DO_WHILE">
                    循环任务
                  </a-select-option>
                  <a-select-option value="TERMINATE">
                    中止任务
                  </a-select-option>
                  <a-select-option value="finish">
                    结束任务
                  </a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
          </a-row>
          <a-row>
            <a-col :span="24">
              <a-form-item label="描述:">
                <a-textarea v-model:value="selectFormData.description" :auto-size="{ minRows: 3, maxRows: 5 }" placeholder="请输入描述" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'http'">
            <a-col :span="24">
              <a-form-item label="请求参数:" name="body" :rules="[{ required: true, message: '请输入请求参数' }]">
                <MonacoEditor v-model="selectFormData.body" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-else>
            <a-col :span="24">
              <a-form-item label="输入参数:" name="inputParameters" :rules="[{ required: true, message: '请输入输入参数' }]">
                <MonacoEditor id="form_item_inputParameters" v-model="selectFormData.inputParameters" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'SWITCH'">
            <a-col :span="24">
              <a-form-item label="分支决策类型:" name="evaluatorType" :rules="[{ required: true, message: '请选择分支决策类型' }]">
                <a-select v-model:value="selectFormData.evaluatorType" placeholder="请选择分支决策类型">
                  <a-select-option value="value-param">
                    值类型决策
                  </a-select-option>
                  <a-select-option value="javascript">
                    JavaScript脚本决策
                  </a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'SWITCH' && selectFormData.evaluatorType === 'value-param'">
            <a-col :span="24">
              <a-form-item label="分支决策参数:" name="expression" :rules="[{ required: true, message: '请输入分支决策参数' }]">
                <a-input v-model:value="selectFormData.expression" placeholder="请输入分支决策参数" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'SWITCH' && selectFormData.evaluatorType === 'javascript'">
            <a-col :span="24">
              <a-form-item label="分支决策表达式:" name="expression" :rules="[{ required: true, message: '请输入分支决策表达式' }]">
                <MonacoEditor v-model="selectFormData.expression" language="javascript" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'HTTP'">
            <a-col :span="24">
              <a-form-item label="请求地址:" name="uri" :rules="[{ required: true, message: '请输入请求地址' }]">
                <a-input v-model:value="selectFormData.uri" placeholder="请输入请求地址" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'HTTP'">
            <a-col :span="24">
              <a-form-item label="请求类型:" name="method" :rules="[{ required: true, message: '请输入请求类型' }]">
                <a-select v-model:value="selectFormData.method" placeholder="请输入请求类型">
                  <a-select-option value="PUT">
                    PUT
                  </a-select-option>
                  <a-select-option value="POST">
                    POST
                  </a-select-option>
                  <a-select-option value="GET">
                    GET
                  </a-select-option>
                  <a-select-option value="DELETE">
                    DELETE
                  </a-select-option>
                  <a-select-option value="PATCH">
                    PATCH
                  </a-select-option>
                  <a-select-option value="HEAD">
                    HEAD
                  </a-select-option>
                  <a-select-option value="OPTIONS">
                    OPTIONS
                  </a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
          </a-row>
          <a-row v-if="selectFormData.nodeType === 'HTTP'">
            <a-col :span="24">
              <a-form-item label="请求头:">
                <a-textarea v-model:value="selectFormData.headers" :auto-size="{ minRows: 3, maxRows: 5 }" placeholder="请输入请求头" />
              </a-form-item>
            </a-col>
          </a-row>
        </a-form>
        <template #extra>
          <a-space>
            <a-button @click="closeInfo">
              取消
            </a-button>
            <a-button type="primary" @click="saveTask">
              保存
            </a-button>
          </a-space>
        </template>
      </a-drawer>
      <!-- 节点/边 详细信息end -->
    </a-layout>
  </a-layout>
</template>

<style lang="less" scpoed>
/** 主体样式 */
.my-x6-layout {
  box-shadow: 1px 1px 10px rgba(0,0,0,.15) ;
  border-radius: 8px;
}
/** 画布边hover */
.my-x6-layout .x6-edge:hover path:nth-child(2){
  stroke: #1890ff;
  stroke-width: 1px;
}
/** 画布边selected */
.my-x6-layout .x6-edge-selected path:nth-child(2){
  stroke: #1890ff;
  stroke-width: 1.5px !important;
}
/** 画布节点selected */
.my-x6-layout .x6-node-selected .node {
  border-color: #1890ff;
  border-radius: 2px;
  box-shadow: 0 0 0 4px #d4e8fe;
}
/** 画布节点(成功状态)selected */
.my-x6-layout .x6-node-selected .node.success {
  border-color: #52c41a;
  border-radius: 2px;
  box-shadow: 0 0 0 4px #ccecc0;
}
/** 画布节点(失败状态)selected */
.my-x6-layout .x6-node-selected .node.failed {
  border-color: #ff4d4f;
  border-radius: 2px;
  box-shadow: 0 0 0 4px #fedcdc;
}
/** toolbar按钮样式 */
.my-x6-layout .x6-toolbar-item {
  align-content: center;
  align-items: center;
  margin: 0;
  color: #595959;
  background-color: transparent;
  border: 0;
  border-radius: 2px;
  outline: none;
  box-shadow: none;
  cursor: pointer;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
/** toolbar按钮hover */
.my-x6-layout .x6-toolbar-item:hover {
  color: #262626;
  background-color: #e0e0e0;
}
/** toolbar按钮禁用 */
.my-x6-layout .x6-toolbar-item-disabled {
  cursor: not-allowed;
  opacity: .4;
}
/** 左侧菜单容器 */
.my-x6-layout .menu-container {
  //box-shadow: 1px 1px 10px rgba(0,0,0,.15) ;
  border-right: 1px solid #ccd0d8;
  border-radius: 8px 0 0 8px;
  background-color: white;
  flex: 0 0 120px !important;
  min-width: 0 !important;
  width: 120px !important;
  transition: flex 1.8s ease-in-out;
}
/** 左侧菜单容器动画 */
.my-x6-layout .menu-out, .my-x6-layout .menu-out .ant-collapse-header {
  transition: opacity 1.8s ease-in-out 1.8s;
}
/** 左侧菜单折叠框样式定制 */
.my-x6-layout .menu-out .ant-collapse-header {
  padding-top: 9px !important;
  padding-bottom: 9px !important;
  padding-left: 15px !important;
  font-size: 12px !important;
}
/** 左侧折叠菜单隐藏样式 */
.my-x6-layout .menu-in, .menu-in .ant-collapse-header {
  padding: 0 !important;
  opacity: 0;
}
/** 菜单元素item样式 */
.my-x6-layout .menu-item {
  height: 36px;
}
/** 菜单元素标题样式 */
.my-x6-layout .menu-slot {
  font-weight: 800;
  height: 40px;
  padding-left: 20px;
  padding-top: 10px;
  background-color: #f5f5f5;
  border-bottom: 1px solid #c2c8d5;
  border-radius: 8px 0 0 0;
}
/** 顶部工具栏容器 */
.my-x6-layout .tool-bar {
  display: flex;
  padding: 5px 5px 5px 10px;
  border-bottom: 1px solid #ccd0d8;
  border-radius: 0 8px 0 0;
  justify-content: space-between;
  //box-shadow: 1px 1px 10px rgba(0,0,0,.15) ;
  background: rgb(245, 245, 245);
  height: 40px;
  line-height: 30px;
}
.x6-toolbar-item .anticon {
  font-size: 14px;
}
/** 顶部工具栏子容器tool-group */
.my-x6-layout .tool-bar .tool-group {
  flex: 1;
}
/** 工具栏分左右，右侧的靠右 */
.my-x6-layout .tool-right {
  text-align: right;
}
.my-x6-layout .tool-right button {
  margin-right: 5px;
}
.my-x6-layout .ant-collapse {
  border: 0;
  background-color: #eeeeee;
}
.my-x6-layout .ant-collapse-item {
  border-color: #c2c8d5;
}
.my-x6-layout .ant-collapse-item:last-child {
  border-radius: 0;
}
.my-x6-layout .ant-collapse-item:last-child .ant-collapse-content {
  border-radius: 0;
}
.my-x6-layout .ant-collapse-arrow {
  left: 10px !important;
}
.menu-container .ant-collapse-content-box {
  padding: 0;
}
/** 左侧菜单隐藏/展示按钮 */
.my-x6-layout .toggle {
  background-color: #f2f2f2;
  position: absolute;
  width: 14px;
  height: 40px;
  top: 50%;
  left: 100%;
  border-top: 1px solid #dedcdc;
  border-right: 1px solid #dedcdc;
  border-bottom: 1px solid #dedcdc;
  /* box-shadow: 1px 1px 2px rgba(0,0,0,.15) ; */
  cursor: pointer;
}
.my-x6-layout .toggle i {
  position: absolute;
  top: 13px;
}
.my-x6-layout .toggle:hover {
  opacity: .7;
}
.my-x6-layout .hide-menu {
  flex: 0 0 0 !important;
}
/** 节点/边 点击展示详情面板 */
.my-x6-layout .node-info {
  overflow-y: auto;
  padding: 10px 25px;
  background-color: white;
  box-shadow: 1px 1px 10px rgba(0,0,0,.15) ;
  position: absolute;
  top: 40px;
  right: 0px;
  height: calc(100% - 40px);
  transition: all 1.8s ease-in-out;
}
/** 节点/边 详情面板显示 */
.my-x6-layout .node-info.show {
  width: 400px;
}
/** 节点/边 详情面板隐藏 */
.my-x6-layout .node-info.hide {
  padding-left: 0;
  padding-right: 0;
  opacity: 0;
  width: 0;
}

.context-menu {
  position: absolute;
  z-index: 1000;
  /* 其他样式 */
}
@keyframes running-line {
  to {
    stroke-dashoffset: -1000;
  }
}
[data-theme='dark'] .my-x6-layout .tool-bar {
  background: #242525;
  border-bottom: 1px solid #595959;
}
[data-theme='dark'] .x6-toolbar-item {
  color: #e7e7e7
}
[data-theme='dark'] .x6-toolbar-item:hover {
  color: #dfdfdf;
  background-color: #777777
}
[data-theme='dark'] .ant-collapse-header {
  background: #242525;
  border-radius: 0;
}
[data-theme='dark'] .menu-container {
  background: #242424;
  border-right: 1px solid #595959;
}
[data-theme='dark'] .menu-slot {
  background: #242525;
  border-bottom: 1px solid #353535;
}
[data-theme='dark'] .x6-node-selected .node {
  border-color: #1890ff;
  border-radius: 2px;
  box-shadow: 0 0 0 4px #376394;
}
</style>
